from types import GenericAlias
from typing import (
    Dict,
    List,
    Optional,
    Tuple,
)

from pydantic import __version__

IS_PYDANTIC_V1: bool = __version__.startswith("1")
""" 是否是 Pydantic V1 版本 """

from pydantic import BaseModel

if IS_PYDANTIC_V1:
    from pydantic.fields import ModelField, FieldInfo

else:
    from pydantic.v1.fields import ModelField, FieldInfo


def parse_model_fields(
    model: type[BaseModel],
    field_dic: Dict[str, str],
    parent_field_name: Optional[str] = None,
    connector: str = ".",
) -> None:
    """
    解析 Pydantic 模型字段数据

    Args:
        model: 模型（BaseModel 的子类）
        field_dic: 解析后的字段字典
        parent_field_name: 父级字段名称
        connector: 字段字典连接符


    Examples:
        >>> from devtools import debug
        >>> from pydantic import BaseModel, Field
        >>>
        >>>
        >>> class Hobby(BaseModel):
        ...     name: str = Field(..., title="名称", min_length=1, max_length=10)
        ...     years: int = Field(..., title="持续时长", gt=1, lt=100)
        ...
        >>>
        >>> class User(BaseModel):
        ...     name: str = Field(..., title="姓名", min_length=3, max_length=20)
        ...     hobbies: List[Hobby] = Field(..., title="爱好")
        >>>
        >>>
        >>> dic = {}
        >>> parse_model_fields(User, dic)
        >>> debug(dic)
        {
            "name": "姓名",
            "hobbies": "爱好",
            "hobbies.name": "爱好.名称",
            "hobbies.years": "爱好.持续时长",
        }
    """

    model_fields: dict[str, ModelField]
    model_fields: dict[str, FieldInfo]

    if IS_PYDANTIC_V1:
        model_fields = model.__fields__

    else:
        model_fields = model.model_fields

    for field_name, field in model_fields.items():
        field_title: str = field.field_info.title or field_name
        field_name_list: List[str] = [field_name]
        field_title_list: List[str] = [field_title]
        field_annotation_list: Tuple[type, ...]

        if parent_field_name is not None:
            field_name_list.insert(0, parent_field_name)
            field_title_list.insert(0, field_dic.get(parent_field_name))

        field_dic[connector.join(field_name_list)] = connector.join(field_title_list)

        if isinstance(field.annotation, GenericAlias):
            field_annotation_list = field.annotation.__args__

        else:
            field_annotation_list = (field.annotation,)

        for annotation in field_annotation_list:
            if not issubclass(annotation, BaseModel):
                continue

            parse_model_fields(annotation, field_dic, field_name)
